#define SEMANTIC

typedef struct TYPE Type;
typedef struct FIELD Field;
typedef struct ARGUMENT Argument;
typedef struct SNODE SNode;

typedef struct SYMBOL Symbol;

#ifndef TREE

#include "tree.h"

#endif

/* element id */
#define SybExtdef 2
#define SybExtDecList 3
#define SybSpecifier 4
#define SybStructSpecifier 5
#define SybOptTag 6
#define SybTag 7
#define SybVarDec 8
#define SybFunDec 9
#define SybVarList 10
#define SybParamDec 11
#define SybCompSt 12
#define SybStmtList 13
#define SybStmt 14
#define SybDefList 15
#define SybDef 16
#define SybDecList 17
#define SybDec 18
#define SybExp 19
#define SybArgs 20
#define SybSEMI 21
#define SybTYPE 23
#define SybID 27
#define SybLB 28
#define SybLP 30
#define SybRETURN 32
#define SybIF 33
#define SybWHILE 35
#define SybASSIGNOP 36
#define SybDIV 37
#define SybAND 38
#define SybOR 39
#define SybRELOP 40
#define SybPLUS 41
#define SybMINUS 42
#define SybSTAR 43
#define SybNOT 44
#define SybDOT 45
#define SybINT 46
#define SybFLOAT 47

#define MAX_SYMBOL_COUNT 256

/* constant type */
#define BASIC_INT 0
#define BASIC_FLOAT 1

/* fill result */
#define SYMBOL_FILL_DONE 0
#define SYMBOL_ALREADY_DECLARED 1
#define FUNCTION_ALREADY_DEFINED 2
#define FIELD_ALREADY_DECLARED 3
#define DUPLICATED_STRUCT_NAME 4
#define STRUCTTURE_NAME 5

/* synthetic attribute kind */
#define NAMEVAL 0
#define CONSTANTINT 1
#define CONSTANTFLOAT 2
#define BASICTYPE 3
#define ARRAYTYPE 4
#define ARGUMTYPE 5
#define DATATYPE 6

struct SNODE {
    Node* node;
    char* name; // name string of identifier
    Type* type;
    SNode* nexDec; // next declaration
    SNode* nexPar; // todo 
    SNode* nexField; // todo 
    int fieldErr; // set true when this is a dupciated field name
};

struct SYMBOL {
    char* name;
    Type* type;
    SNode* args; // used for function
};

struct TYPE {
    enum {
        BASIC,
        ARRAY,
        STRUCTTURE,
        FUNC_BASIC,
        UNDEFINED
    } kind;

    union {
        int intval;
        float floatval;
    } constant;

    union {
        int basic;
        
        struct {
            Type* type; // element type 
            int size; // array size
        } array;

        struct {
            SNode* field; // field list
            int count; // field count
        } struc;

        struct { /* non-use */
            Type* type;
            Argument* argument; // argument list
            int count; // argument count
        } func;
    } info;
    
};

// easy to connect
/* non-use */
struct FIELD {
    char *name; // field name
    Type type; // field type
    Field* nexf; // next field
};

// easy to connect
/* non-use */
struct ARGUMENT {
    char *name;  // argument name
    Type type; // argument type
    Argument* nexa; // next argument
};


/**
 * @brief print info of semantic error
 * 
 * @param type error type
 * @param lineno error line number
 * @param msg error message
 * @param sym symbol name
 */
void serror(int type, int lineno, char *msg, char* sym);

/**
 * @brief main process of semantic analysis
 * 
 * @param root root node of grammer tree
 */
void semanticAnalysis(Node* root, char* out);

/**
 * @brief allocate attribtue node memory and collect symbols in declarations
 * 
 * @param node node inserted in grammer analysis
 */
void prepareForSemanticAnalysis(Node* node);

/**
 * @brief insert symbol name into symbol array
 * 
 * @param name name of symbol to insert
 */
void insertSymbol(char* name);

/**
 * @brief create a symbol table for symbols colected in preparation
 * 
 */
void createSymbolTable();

/**
 * @brief sort symbols collected
 * 
 */
void sortSymbols();

/**
 * @brief remove duplicated symbol name
 * 
 */
void getUniqueSymbol();

/**
 * @brief get symbol index in the symbol table by name
 * 
 * @param name name of symbol
 * @return int symbol index in the symbol table
 */
int getSymbolIndex(char* name);

/**
 * @brief check fill result and show error message when error occurs
 * 
 * @param status fill result
 * @param node node carrying the symbol info
 */
void fillError(int status, SNode* node);

/**
 * @brief fill a list of symbols with same type into tbale
 * 
 * @param specifier carry the symbol type
 * @param extdeclist a list of symbols
 */
void fillSymbols(SNode* specifier, SNode* extdeclist);


/**
 * @brief fill a symbol into table
 * 
 * @param name symbol name
 * @param type symbol type
 * @param address symbol kind: 0 common; 1 struct field; 2 struct
 * @return int fill result
 */
int fillSymbol(char* name, Type* type, int address);

/**
 * @brief fill a list of struct fileds with same type into table
 * 
 * @param specifier carry symbol type
 * @param extdeclist a list of symbols
 */
void fillStructSymbols(SNode* specifier, SNode* extdeclist);

/**
 * @brief fill a struct symbol into table
 * 
 * @param snode carry struct info
 */
void fillStruct(SNode* snode);

/**
 * @brief enclose FillFunction with FillError
 * 
 * @param specifier carry return type
 * @param func carry function info
 */
void fillFunctions(SNode* specifier, SNode* func);

/**
 * @brief fill a function into table
 * 
 * @param specifier carry return type
 * @param func carry function info
 * 
 * @return int fill
 */
int fillFunction(SNode* specifier, SNode* func);

/**
 * @brief assign type attribute to a node
 * 
 * @param specifier carry type info
 * @param var node to be assigned
 */
void typeAssign(SNode* specifier, SNode* var);

/**
 * @brief assign synthetic attribute
 * 
 * @param pa parent node
 * @param ch child node
 * @param type attribute type
 */
void synAssign(SNode* pa, SNode* ch, int type);

/**
 * @brief assign attribute using lexical value
 * 
 * @param snode node to be assigned
 * @param node node carry lexical info
 * @param type attribute type
 */
void lexAssign(SNode* snode, Node* node, int type);

/**
 * @brief assign undefined type to a node
 * 
 * @param snode node to be assigned
 */
void udfAssign(SNode* snode);

/**
 * @brief assign attribute from symbol table
 * 
 * @param snode node to be assign
 * @param index index of symbol in the symbol table
 * @param type attribute type
 */
void tabAssign(SNode* snode, int index, int type);

/**
 * @brief assign struct info to a node
 * 
 * @param snode node to be assing
 * @param node node carry struct info
 */
void stuAssign(SNode* snode, Node* node);

int isVarStructure(SNode* snode);

/**
 * @brief check if a field is defined in a structure
 * 
 * @param snode snode carry struct info
 * @param field filed to be check
 * @return int true if defined or false if not
 */
int isFieldDefined(SNode* snode, SNode *field);

/**
 * @brief check if two struct have same structure
 * 
 * @param opt1 struct 1
 * @param opt2 struct 2
 * @return int true if same of false is not
 */
int checkField(SNode* opt1, SNode* opt2);

/**
 * @brief check if funtion call match function defination
 * 
 * @param index function symbol index in the table
 * @param cargs params the caller specified
 * @return int true if match or false if not
 */
int checkFuncArgs(int index, SNode* cargs);


/* printer */
void showSymbols(char* sybs[], int cnt);
void showSymblos();
void showSymbol(int index);
void println();
void showStructField(char* name);
void showArrayType(Type* type);
void showArgs(SNode* arg);

/* optrand checker */
int isOptrandTypeSame(SNode* opt1, SNode* opt2);
int isOperandBasicType(SNode* opt);
int checkBasic(SNode* opt1, SNode* opt2);
int isOperandTypeInt(SNode* opt);
int isLeftHandVar(SNode* opt);

/* operator checker */
int isAlgOperator(Node* node);
int isLogOperator(Node* node);
int isAsnOperator(Node* node);

int isSymbolArray(char* name);